/******************************************************/
/* Goblin's Cube - Rubik's cube game for Wii Homebrew */
/* Copyright (C) 2009 Ricardo Bueno Cordeiro          */
/* Licensed under de GNU General Public License v2.0  */
/*   See license_gplv2.txt for detalis                */
/******************************************************/

#include <gccore.h>
#include <fat.h>
#include <stdio.h>
#include <unistd.h>

#include "draw.h"
#include "control_highscore.h"
#include "filesystem.h"
#include "cube.h"

static const char game_folder[] = "/apps/goblin";
static const char local_highscore_filename[] = "goblins_cube.data";

ControlHighscore::ControlHighscore() {
	this->load_local_score();
	this->naming_result = -1;
}

void ControlHighscore::get_filename(char *full_path, const char *filename) {
	if (filesystem_check_file(game_folder))
		sprintf(full_path, "%s/%s", game_folder, filename);
	else
		sprintf(full_path, "%s", filename);
}

void ControlHighscore::load_local_score() {
	this->num_local = 0;

	if (!filesystem_is_working())
		return;
	
	char filename[256];
	this->get_filename(filename, local_highscore_filename);
	
	FILE *f = fopen(filename, "rb");

	if (f == NULL)
		return;

	u16 version;
	size_t t = fread(&version, sizeof(version), 1, f);
	if (t == 0) {
		fclose(f);
		return;
	}

	t = fread(&this->num_local, sizeof(this->num_local), 1, f);
	if (t == 0) {
		fclose(f);
		return;
	}

	if (this->num_local > NUM_HIGHSCORES) {
		fclose(f);
		return;
	}

	for (int i = 0; i < this->num_local; i++) {
		t = fread(this->local_highscore[i].name, sizeof(this->local_highscore[i].name[0]), 3, f);
		if (t != 3) {
			fclose(f);
			return;
		}

		t = fread(&this->local_highscore[i].time, sizeof(this->local_highscore[i].time), 1, f);
		if (t == 0) {
			fclose(f);
			return;
		}
	}

	fclose(f);
}

void ControlHighscore::save_local_score() {
	if (!filesystem_is_working())
		return;

	char filename[256];
	this->get_filename(filename, local_highscore_filename);

	FILE *f = fopen(filename, "wb");

	if (f == NULL)
		return;

	u16 version = 0x0001;
	size_t t = fwrite(&version, sizeof(version), 1, f);
	if (t == 0) {
		fclose(f);
		return;
	}

	t = fwrite(&this->num_local, sizeof(this->num_local), 1, f);
	if (t == 0) {
		fclose(f);
		return;
	}

	for (int i = 0; i < this->num_local; i++) {
		t = fwrite(this->local_highscore[i].name, sizeof(this->local_highscore[i].name[0]), 3, f);
		if (t != 3) {
			fclose(f);
			return;
		}

		t = fwrite(&this->local_highscore[i].time, sizeof(this->local_highscore[i].time), 1, f);
		if (t != 1) {
			fclose(f);
			return;
		}
	}

	fclose(f);
}

int ControlHighscore::update(WPADData *wiimote_data, int state) {
	if (state != CONTROL_FOREGROUND)
		return 0;
		
	if (this->naming_result < 0) {
		if (wiimote_data->btns_d & WPAD_BUTTON_A)
			Cube::cube.scramble();
	} else {
		if (wiimote_data->btns_d & WPAD_BUTTON_LEFT)
			this->naming_current_letter = (this->naming_current_letter + 2) % 3;
		if (wiimote_data->btns_d & WPAD_BUTTON_RIGHT)
			this->naming_current_letter = (this->naming_current_letter + 1) % 3;

		if (wiimote_data->btns_d & WPAD_BUTTON_UP) {
			u8 l = this->local_highscore[this->naming_result].name[this->naming_current_letter];
			l = ((l - 'A' + 1) % 26) + 'A';
			this->local_highscore[this->naming_result].name[this->naming_current_letter] = l;
		}
		if (wiimote_data->btns_d & WPAD_BUTTON_DOWN) {
			u8 l = this->local_highscore[this->naming_result].name[this->naming_current_letter];
			l = ((l - 'A' + 25) % 26) + 'A';
			this->local_highscore[this->naming_result].name[this->naming_current_letter] = l;
		}

		if (wiimote_data->btns_d & WPAD_BUTTON_A) {
			this->naming_result = -1;
			this->save_local_score();
		}
	}

	return 0;
}

void ControlHighscore::draw(int state) {
	if (state != CONTROL_FOREGROUND)
		return;
}

void ControlHighscore::draw_highscore_board(f32 x, f32 y, const char *title, int num, struct score_t *score) {
	GXColor color;

	// Draws a black rectangle to clear the area
	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);

	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
		GX_Position3f32(x, -y, 0.0);
		GX_Color4u8(0, 0, 0, 255);
		GX_Position3f32(x, -y + 372, 0.0);
		GX_Color4u8(0, 0, 0, 255);
		GX_Position3f32(x + 380, -y + 372, 0.0);
		GX_Color4u8(0, 0, 0, 255);
		GX_Position3f32(x + 380, -y, 0.0);
		GX_Color4u8(0, 0, 0, 255);
	GX_End();

	// Write the scores
	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);

	DR_draw_text(x + 20, y - 32, (GXColor){ 255, 255, 255, 255}, "Rank");
	DR_draw_text(x + 120, y - 32, (GXColor){ 255, 255, 255, 255}, "Initials");
	DR_draw_text(x + 270, y - 32, (GXColor){ 255, 255, 255, 255}, "Time");

	for (int i = 0; i < num; i++) {
		color = (GXColor){ 255, 255, 255, 255};
		u16 style[3] = { FTGX_JUSTIFY_CENTER, FTGX_JUSTIFY_CENTER, FTGX_JUSTIFY_CENTER };
		
		if (this->naming_result == i) {
			color = (GXColor){ 150, 150, 150, 255};
			style[this->naming_current_letter] |= FTGX_STYLE_UNDERLINE;
		}

		DR_draw_text(x + 20, y - 72 - 32 * i, color, "%hu", i + 1);
		for (int j = 0; j < 3; j++)
			DR_draw_text(x + 120 + 32 * j, y - 72 - 32 * i, color, style[j], "%c", score[i].name[j]);
		DR_draw_text(x + 270, y - 72 - 32 * i, color, "%.2f", score[i].time);
	}

	// Draws a red borders at our table
	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);

	GX_Begin(GX_LINESTRIP, GX_VTXFMT0, 5);
		GX_Position3f32(x, -y, 0.0);
		GX_Color4u8(255, 0, 0, 255);
		GX_Position3f32(x, -y + 372, 0.0);
		GX_Color4u8(255, 0, 0, 255);
		GX_Position3f32(x + 380, -y + 372, 0.0);
		GX_Color4u8(255, 0, 0, 255);
		GX_Position3f32(x + 380, -y, 0.0);
		GX_Color4u8(255, 0, 0, 255);
		GX_Position3f32(x, -y, 0.0);
		GX_Color4u8(255, 0, 0, 255);
	GX_End();

	GX_Begin(GX_LINES, GX_VTXFMT0, 2);
		GX_Position3f32(x, -y + 42, 0.0);
		GX_Color4u8(255, 0, 0, 255);
		GX_Position3f32(x + 380, -y + 42, 0.0);
		GX_Color4u8(255, 0, 0, 255);
	GX_End();

	GX_ClearVtxDesc();
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);
}

void ControlHighscore::text(int state) {
	if (state != CONTROL_FOREGROUND)
		return;

	this->draw_highscore_board(80, 832, "Local highscore", this->num_local, this->local_highscore);

	if (this->naming_result < 0)
		DR_draw_text(500, 80, (GXColor){ 255, 255, 255, 255}, FTGX_JUSTIFY_CENTER, "Press A to start a new game");
	else {
		DR_draw_text(500, 100, (GXColor){ 255, 255, 255, 255}, FTGX_JUSTIFY_CENTER, "Use the DIRECTION PAD to select your initials,");
		DR_draw_text(500, 68, (GXColor){ 255, 255, 255, 255}, FTGX_JUSTIFY_CENTER, "then press A to save your score");
	}
}

int ControlHighscore::add_local_score(const char *name, f32 time) {
	int i = 0;

	while (i < this->num_local) {
		if (this->local_highscore[i].time > time)
			break;
		i++;
	}
	
	if ((i < NUM_HIGHSCORES) && (i >= 0)) {
		int j = this->num_local - 1;
		
		while (j >= i) {
			this->local_highscore[j + 1].name[0] = this->local_highscore[j].name[0];
			this->local_highscore[j + 1].name[1] = this->local_highscore[j].name[1];
			this->local_highscore[j + 1].name[2] = this->local_highscore[j].name[2];
			this->local_highscore[j + 1].time = this->local_highscore[j].time;
			j--;
		}
		
		this->local_highscore[i].name[0] = name[0];
		this->local_highscore[i].name[1] = name[1];
		this->local_highscore[i].name[2] = name[2];
		this->local_highscore[i].time = time;
		
		if (this->num_local < NUM_HIGHSCORES)
			this->num_local++;
			
		return i;
	}
	
	return -1;
}


void ControlHighscore::just_solved() {
	int result = this->add_local_score("AAA", Cube::cube.get_current_time());
	
	if (result < 0)
		return;

	this->naming_result = result;	
	this->naming_current_letter = 0;
}
